package com.yvan;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;

import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * DateUtils 日期工具类
 *
 * @author luoyifan 2014/10/2 4:02:52
 */
public class DateUtils {

    public static final String SHORT_DATE_FORMAT_STR = "yyyy-MM-dd";
//    private static final SimpleDateFormat FORMAT_DATE_TIME;
//    private static final SimpleDateFormat FORMAT_TIME;
//    private static final SimpleDateFormat FORMAT_DATE;
//    private static final SimpleDateFormat FORMAT_MONTH_DATE;
//
//    private static final SimpleDateFormat FORMAT_DATE_NOZONE;
//    private static final SimpleDateFormat FORMAT_DATE_TIME_NOZONE;
//
//    private static final SimpleDateFormat FORMAT_YYYYMMDD;
//    private static final SimpleDateFormat FORMAT_DATE_TIME_CHINESE;
//
//    private static final SimpleDateFormat FORMAT_DATE_TIME_SPRIT;
//
//    private static final SimpleDateFormat FORMAT_DATE_OTHER_TIME;
    public static final String LONG_DATE_FORMAT_STR = "yyyy-MM-dd HH:mm:ss";
    public static final String LONG_DATA_FORMAT_STR2 = "yyyy/MM/dd HH:mm:ss";
    public static final DateTimeFormatter SHORT_DATE_FORMAT = DateTimeFormat.forPattern(SHORT_DATE_FORMAT_STR);
    public static final DateTimeFormatter LONG_DATE_FORMAT = DateTimeFormat.forPattern(LONG_DATE_FORMAT_STR);
    public static final String EARLY_TIME = "00:00:00";
    public static final String LATE_TIME = "23:59:59";
    private static final TimeZone TZ = TimeZone.getTimeZone("GMT+:08:00");
    private static final DateTimeFormatter FORMAT_DATE_TIME;
    private static final DateTimeFormatter FORMAT_TIME;
    private static final DateTimeFormatter FORMAT_DATE;
    private static final DateTimeFormatter FORMAT_MONTH_DATE;
    private static final DateTimeFormatter FORMAT_DATE_NOZONE;
    private static final DateTimeFormatter FORMAT_DATE_TIME_NOZONE;
    private static final DateTimeFormatter FORMAT_YYYYMMDD;
    private static final DateTimeFormatter FORMAT_DATE_TIME_CHINESE;
    private static final DateTimeFormatter FORMAT_DATE_TIME_SPRIT;
    private static final DateTimeFormatter FORMAT_DATE_OTHER_TIME;

    static {
        FORMAT_DATE_TIME = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
        //FORMAT_DATE_TIME.setTimeZone(TZ);

        FORMAT_TIME = DateTimeFormat.forPattern("HH:mm:ss");
        //FORMAT_TIME.setTimeZone(TZ);

        FORMAT_DATE = DateTimeFormat.forPattern("yyyy-MM-dd");
        //FORMAT_DATE.setTimeZone(TZ);

        FORMAT_MONTH_DATE = DateTimeFormat.forPattern("yyyyMM");
        //FORMAT_MONTH_DATE.setTimeZone(TZ);

        FORMAT_YYYYMMDD = DateTimeFormat.forPattern("yyyyMMdd");
        //FORMAT_YYYYMMDD.setTimeZone(TZ);

        FORMAT_DATE_TIME_CHINESE = DateTimeFormat.forPattern("yyyy年MM月dd日 HH:mm");
        //FORMAT_DATE_TIME_CHINESE.setTimeZone(TZ);

        FORMAT_DATE_NOZONE = DateTimeFormat.forPattern("yyyy-MM-dd");
        FORMAT_DATE_TIME_NOZONE = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");

        FORMAT_DATE_TIME_SPRIT = DateTimeFormat.forPattern("yyyy/MM/dd HH:mm:ss");

        FORMAT_DATE_OTHER_TIME = DateTimeFormat.forPattern("yyyy.MM.dd");
    }


    /**
     * 将时间字符串转为时间戳
     * <p>time 格式为 yyyy-MM-dd HH:mm:ss</p>
     *
     * @param time 时间字符串
     * @return 毫秒时间戳
     */
    public static long string2Millis(final String time) {
        return string2Millis(time, FORMAT_DATE_TIME);
    }

    /**
     * 将时间字符串转为时间戳不带时区
     * <p>time 格式为 yyyy-MM-dd HH:mm:ss</p>
     *
     * @param time 时间字符串
     * @return 毫秒时间戳
     */
    public static long string2MillisNozone(final String time) {
        return string2Millis(time, FORMAT_DATE_TIME_NOZONE);
    }

    /**
     * 将时间字符串转为时间戳
     * <p>time 格式为 format</p>
     *
     * @param time   时间字符串
     * @param format 时间格式
     * @return 毫秒时间戳
     */
    public static long string2Millis(final String time, final DateTimeFormatter format) {
        try {
            return format.parseDateTime(time).getMillis();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        return -1;
    }

    /**
     * 格式化时间为yyyy-MM-dd HH:mm:ss，不设置时区
     *
     * @param str
     * @return
     */
    public static Date formatDateTimeNoZone(String str) {
        try {
            return FORMAT_DATE_TIME_NOZONE.parseDateTime(str).toDate();
        } catch (IllegalArgumentException e) {
            return new Date();
        }
    }

    /**
     * 格式化时间为yyyy-MM-dd HH:mm:ss，不设置时区
     *
     * @param str
     * @return
     */
    public static Date formatDateOtherTime(String str) {
        try {
            return FORMAT_DATE_OTHER_TIME.parseDateTime(str).toDate();
        } catch (IllegalArgumentException e) {
            return new Date();
        }
    }

    /**
     * 格式化yyyy/MM/dd HH:mm:ss时间为DATE，不设置时区
     *
     * @param str
     * @return
     */
    public static Date formatDateTimeSprit(String str) {
        try {
            return FORMAT_DATE_TIME_SPRIT.parseDateTime(str).toDate();
        } catch (IllegalArgumentException e) {
            return new Date();
        }
    }

    /**
     * 2016-02-23 08:09:01
     */
    public static Timestamp fromPatter(String value, String patter, Timestamp defaultValue) {
        SimpleDateFormat sdf = new SimpleDateFormat(patter);
        try {
            return new Timestamp(sdf.parse(value).getTime());
        } catch (Exception e) {
            return defaultValue;
        }
    }

    public static Calendar getCalendar() {
        return Calendar.getInstance(TZ);
    }

    public static String toDateTimeStr(Date date) {
        return new DateTime(date).toString(FORMAT_DATE_TIME.withZone(DateTimeZone.forTimeZone(TZ)));
    }

    public static String toTimeStr(Date date) {
        return new DateTime(date).toString(FORMAT_TIME.withZone(DateTimeZone.forTimeZone(TZ)));
    }

    public static String toDateStr(Date date) {
        return new DateTime(date).toString(FORMAT_DATE);
    }

    public static String toMonthStr(Date date) {
        return new DateTime(date).toString(FORMAT_MONTH_DATE.withZone(DateTimeZone.forTimeZone(TZ)));
    }

    public static Integer toyyyyMMdd(Date date) {
        return Integer.parseInt(new DateTime(date).toString(FORMAT_YYYYMMDD.withZone(DateTimeZone.forTimeZone(TZ))));
    }

    /**
     * 2016-02-23
     */
    public static Date fromDate(String v) {
        try {
            return FORMAT_DATE.parseDateTime(v).toDate();
        } catch (IllegalArgumentException e) {
            return new Date();
        }
    }

    /**
     * 20160223
     */
    public static Date fromDate(Integer vs) {
        try {
            String v = Integer.toString(vs);
            Calendar calc = getCalendar();
            calc.set(Calendar.YEAR, Integer.parseInt(v.substring(0, 4)));
            calc.set(Calendar.MONTH, Integer.parseInt(v.substring(4, 6)) - 1);
            calc.set(Calendar.DAY_OF_MONTH, Integer.parseInt(v.substring(6, 8)));

            calc.set(Calendar.HOUR_OF_DAY, 0);
            calc.set(Calendar.MINUTE, 0);
            calc.set(Calendar.SECOND, 0);
            return calc.getTime();

        } catch (Exception e) {
            return new Date();
        }
    }

    public static int getYear(Timestamp now) {
        Calendar calc = getCalendar();
        calc.setTime(new Date(now.getTime()));
        return calc.get(Calendar.YEAR);
    }

    public static int getMonth(Timestamp now) {
        Calendar calc = getCalendar();
        calc.setTime(new Date(now.getTime()));
        return calc.get(Calendar.MONTH);
    }

    public static int getDay(Timestamp now) {
        Calendar calc = getCalendar();
        calc.setTime(new Date(now.getTime()));
        return calc.get(Calendar.DAY_OF_MONTH);
    }

    /**
     * 按最短字符串长度表示年月日
     * 1位年+1位月+1位日
     * 年前年份-startYear 采用36进制(0-9/A-Z)
     * 月份 采用36进制(0-9/A-Z)
     * 日 采用36进制(0-9/A-Z)
     */
    public static String getShortYMD(Timestamp time, int startYear) {
        return "" + YvanUtil.getShortDig(getYear(time) - startYear) +
                YvanUtil.getShortDig(getMonth(time)) +
                YvanUtil.getShortDig(getDay(time));
    }


    /**
     * 2016-02-23 08:09:01
     */
    public static Date fromDateTime(String v) {
        try {
            return FORMAT_DATE_TIME.withZone(DateTimeZone.forTimeZone(TZ)).parseDateTime(v).toDate();
        } catch (IllegalArgumentException e) {
            return new Date();
        }
    }

    /**
     * <pre>
     * 2016-02-23 return 2016-02-24
     * 2016-02-29 return 2016-03-01
     * </pre>
     */
    public static Date addDay(Date v, int days) {
        final Calendar calc = getCalendar();
        calc.setTime(v);
        calc.add(Calendar.DAY_OF_WEEK, days);
        return calc.getTime();
    }

    /**
     * 获取按天累加的日期序列
     */
    public static List<Date> getDaySeq(Date dt1, Date dt2) {
        final Calendar calc = getCalendar();

        List<Date> r = new ArrayList<>();
        for (calc.setTime(dt1); calc.getTime().compareTo(dt2) <= 0; calc.add(Calendar.DAY_OF_WEEK, 1)) {
            r.add(calc.getTime());
        }
        return r;
    }

    /**
     * <pre>
     * 获取按月累加的日期序列, 例如 201601 201702
     * 返回  201601 201602 201603
     * </pre>
     */
    public static List<String> getMonthSeq(int d1, int d2) {
        Date dt1 = fromDate(Integer.parseInt(Integer.toString(d1) + "01"));
        Date dt2 = fromDate(Integer.parseInt(Integer.toString(d2) + "01"));
        return getMonthSeq(dt1, dt2);
    }

    /**
     * 获取按月累加的日期序列, 返回 201601 201602 201603
     */
    public static List<String> getMonthSeq(Date dt1, Date dt2) {
        final Calendar calc = Calendar.getInstance();

        calc.setTime(dt1);
        if (calc.get(Calendar.DAY_OF_MONTH) > 1) {
            dt1 = fromDate(Integer.parseInt(toMonthStr(dt1).substring(0, 6) + "01"));
        }
        calc.setTime(dt2);
        if (calc.get(Calendar.DAY_OF_MONTH) > 1) {
            dt2 = fromDate(Integer.parseInt(toMonthStr(dt2).substring(0, 6) + "01"));
        }

        List<String> r = new ArrayList<>();
        for (calc.setTime(dt1); calc.getTime().compareTo(dt2) <= 0; calc.add(Calendar.MONTH, 1)) {
            r.add(toMonthStr(calc.getTime()));
        }
        return r;
    }

    public static void main(String[] args) {
        System.out.println(new SimpleDateFormat("M.dd").format(fromDate(20171109)));
        String d1 = "2016-02-23";
        String d2 = "2016-03-02";
        System.out.println(d1);

        System.out.println(toDateTimeStr(fromDate(20161018)));

        // System.out.println(fromDate(d1).compareTo(fromDate(d2)));
        // System.out.println(fromDate(d2).compareTo(fromDate(d1)));
        // System.out.println(fromDate(d1).compareTo(fromDate(d1)));

        List<Date> seq = getDaySeq(fromDate(d1), fromDate(d2));
        for (Date d : seq) {
            System.out.println(toDateStr(d));
        }
    }

    public static Timestamp now() {
        return new Timestamp(System.currentTimeMillis());
    }

    public static int seconds(Timestamp t1, Timestamp t2) {
        return Conv.NI((t1.getTime() - t2.getTime()) / 1000);
    }

    public static Timestamp addSeconds(Timestamp t1, int seconds) {
        return new Timestamp(t1.getTime() + seconds * 1000);
    }


    /**
     * 用于设置后台搜索的时间项 袁华
     * 返回精确到天
     *
     * @param map
     * @param timeStr
     * @param identify
     */
    public static void setTime(Map map, String timeStr, String identify) {
        if (!StringUtils.isEmpty(timeStr)) {
            String[] vs = timeStr.split("至");
            if (vs.length == 2) {
                Timestamp dt1 = new Timestamp(DateUtils.formatDateNoZone(vs[0].trim()).getTime());
                Timestamp dt2 = new Timestamp(DateUtils.addDay(DateUtils.formatDateNoZone(vs[1].trim()), 1).getTime());
                map.put(identify + "Begin", dt1);
                map.put(identify + "End", dt2);
            }
        }
    }

    /**
     * 用于设置后台搜索的时间项 袁华
     * 返回精确到天
     *
     * @param map
     * @param timeStr
     * @param start
     * @param end
     */
    public static void setTime(Map map, String timeStr, String start, String end) {
        if (!StringUtils.isEmpty(timeStr)) {
            String[] vs = timeStr.split("至");
            if (vs.length == 2) {
                Timestamp dt1 = new Timestamp(DateUtils.formatDateNoZone(vs[0].trim()).getTime());
                Timestamp dt2 = new Timestamp(DateUtils.addDay(DateUtils.formatDateNoZone(vs[1].trim()), 1).getTime());
                map.put(start, dt1);
                map.put(end, dt2);
            }
        }
    }

    /**
     * 格式化时间为yyyy-MM-dd，不设置时区
     *
     * @param str
     * @return
     */
    public static Date formatDateNoZone(String str) {
        try {
            return FORMAT_DATE_NOZONE.parseDateTime(str).toDate();
        } catch (IllegalArgumentException e) {
            return new Date();
        }
    }

    public static String toChineseFmt(Timestamp startTime) {
        return new DateTime(new Date(startTime.getTime())).toString(FORMAT_DATE_TIME_CHINESE);
    }

    /**
     * 使用参数Format格式化Date成字符串
     *
     * @return String
     */
    public static String format(Date date, String pattern) {
        return date == null ? "" : new SimpleDateFormat(pattern).format(date);
    }

    /**
     * 得到某个日期在这一天中时间最早的日期对象
     *
     * @param date
     * @return
     * @throws ParseException
     */

    public static Date getEarlyInTheDay(Date date) {
        String dateString = new DateTime(date).toString(SHORT_DATE_FORMAT) + " " + EARLY_TIME;
        try {
            return LONG_DATE_FORMAT.parseDateTime(dateString).toDate();
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("parser date error.", e);
        }
    }

    /**
     * 得到某个日期在这一天中时间最晚的日期对象
     */
    public static Date getLateInTheDay(Date date) {
        String dateString = new DateTime(date).toString(SHORT_DATE_FORMAT) + " " + LATE_TIME;
        try {
            return LONG_DATE_FORMAT.parseDateTime(dateString).toDate();
        } catch (IllegalArgumentException e) {
            throw new RuntimeException("parser date error.", e);
        }
    }

    /*
     * 获取前后日期 i为正数 向后推迟i天，负数时向前提前i天
     * @author XP
     * @time 2016年11月25日
     */
    public static Date getDate(int i) {
        Date dat = null;
        Calendar cd = Calendar.getInstance();
        cd.add(Calendar.DATE, i);
        dat = cd.getTime();
        SimpleDateFormat dformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Timestamp date = Timestamp.valueOf(dformat.format(dat));
        return date;
    }

    /*
     * 获取当前时间加或减一段时间以后的日期 , i为正数 向后推迟，负数时向前提前
     * @param i 增量, calendar 类型
     * @author XP
     * @time 2016年11月25日
     */
    public static Date getDate(int i, int calendar) {
        Date dat = null;
        Calendar cd = Calendar.getInstance();
        cd.add(calendar, i);
        dat = cd.getTime();
        SimpleDateFormat dformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Timestamp date = Timestamp.valueOf(dformat.format(dat));
        return date;
    }

    /**
     * 时间戳转换成日期格式字符串
     *
     * @param milliseconds 精确到秒的字符串
     * @param format
     * @return
     */
    public static String timeStamp2Date(String milliseconds, String format) {
        if (milliseconds == null || milliseconds.isEmpty() || milliseconds.equals("null")) {
            return "";
        }
        if (format == null || format.isEmpty()) {
            format = "yyyy-MM-dd HH:mm:ss";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date(Long.valueOf(milliseconds)));
    }

    /**
     * 日期格式字符串转换成时间戳
     *
     * @param date_str 字符串日期
     * @param format   如：yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static String date2TimeStamp(String date_str, String format) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return String.valueOf(sdf.parse(date_str).getTime());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public static Long date2TimeStampLong(String date_str, String format) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            return sdf.parse(date_str).getTime();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getSdTimeOut() {
        Calendar c = Calendar.getInstance();
        c.add(Calendar.MINUTE, 180);
        return new SimpleDateFormat("yyyyMMddHHmmss").format(c.getTime());
    }

    /**
     * 判断是否为yyyy-MM-dd格式字符串时间
     *
     * @param dateStr
     * @return
     */
    public static boolean isLongDateFormatStr(String dateStr) {
        DateFormat formatter = new SimpleDateFormat(LONG_DATE_FORMAT_STR);
        formatter.setLenient(false);
        try {
            Date date = formatter.parse(dateStr);
            System.out.println(date);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取指定日期时间戳
     *
     * @param dateTimeStr
     * @return
     * @throws Exception
     */
    public static long getMillsecFromStr(String dateTimeStr) {
        SimpleDateFormat sdf = new SimpleDateFormat(LONG_DATE_FORMAT_STR);
        if (dateTimeStr == null) {
            return 0;
        }
        try {

            Date d = sdf.parse(dateTimeStr);
            return d.getTime();
        } catch (Exception e) {
            return 0;
        }
    }
}
